package com.zhangzhan.gulimallorder.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.zhangzhan.gulimallcommcon.tos.MemberTo;
import com.zhangzhan.gulimallcommcon.tos.SkuCheckInventoryTo;
import com.zhangzhan.gulimallcommcon.util.MyCollUtil;
import com.zhangzhan.gulimallcommcon.util.R;
import com.zhangzhan.gulimallorder.entity.OrderEntity;
import com.zhangzhan.gulimallorder.entity.OrderItemEntity;
import com.zhangzhan.gulimallorder.feign.CartFeignService;
import com.zhangzhan.gulimallorder.feign.MemberFeignService;
import com.zhangzhan.gulimallorder.feign.ProductFeignService;
import com.zhangzhan.gulimallorder.feign.WareFeignService;
import com.zhangzhan.gulimallorder.interceptor.OrderInterceptor;
import com.zhangzhan.gulimallorder.service.OrderItemService;
import com.zhangzhan.gulimallorder.service.OrderService;
import com.zhangzhan.gulimallorder.service.OrderWebService;
import com.zhangzhan.gulimallorder.tos.OrderCreateTo;
import com.zhangzhan.gulimallorder.tos.SpuInfoTo;
import com.zhangzhan.gulimallorder.vos.*;
import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.zhangzhan.gulimallcommcon.constant.IdempotencyConstant.PAY_UID;
import static com.zhangzhan.gulimallcommcon.constant.orderAndWareUnLockCons.OrderCancelMqConstant.ORDER_CREATE_ORDER;
import static com.zhangzhan.gulimallcommcon.constant.orderAndWareUnLockCons.OrderCancelMqConstant.ORDER_EVENT_EXCHANGE;

/**
 * @author 张一恒
 * @version 1.0
 * @description:
 * @date 2024/6/30 11:35
 */
@Service
@Slf4j
public class OrderWebServiceImpl implements OrderWebService {

    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private CartFeignService cartFeignService;

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private WareFeignService wareFeignService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Override
    public ConfirmVo toTrade() {
        MemberTo memberTo = OrderInterceptor.MEMBER.get();
        ConfirmVo confirmVo = new ConfirmVo();

        //解决异步调用线程之间feign客户端共享请求头问题
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> address = CompletableFuture.runAsync(() -> {
            //远程获取用户地址信息
            List<MemberAddrVo> memberAddrList = memberFeignService.getMemberAddrList(memberTo.getId());

            //保证幂等性
            confirmVo.setUid(UUID.randomUUID().toString().replaceAll("-", ""));
            stringRedisTemplate.opsForValue().set(PAY_UID + memberTo.getId(), confirmVo.getUid(), 5, TimeUnit.MINUTES);
            confirmVo.setMemberAddrVos(memberAddrList);
        }, executor);

        CompletableFuture<Void> carts = CompletableFuture.supplyAsync(() -> {
            //远程获取用户购物车信息
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberCartVo> memberCarts = cartFeignService.getMemberCarts();
            confirmVo.setMemberCartVos(memberCarts);
            return memberCarts;
        }, executor).thenAcceptAsync((res) -> {
            //查询库存
            if (MyCollUtil.isNotEmpty(res)) {
                List<Long> skuIds = res.stream().map(MemberCartVo::getSkuId).toList();
                List<SkuCheckInventoryTo> tos = wareFeignService.checkInventory(skuIds);
                confirmVo.setHasInventory(tos.stream().collect(Collectors.toMap(SkuCheckInventoryTo::getSkuId, SkuCheckInventoryTo::getCheck)));
            }
        }, executor);


        try {
            CompletableFuture.allOf(address, carts).get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //优惠信息
        confirmVo.setIntegration(memberTo.getIntegration());
        return confirmVo;
    }

    @Transactional
    @Override
    public SubmitOrderRespVo toPay(SubmitPayVo submitPayVo) {
        SubmitOrderRespVo vo = new SubmitOrderRespVo();
        MemberTo memberTo = OrderInterceptor.MEMBER.get();
        //保证幂等性
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long res = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), List.of(PAY_UID + memberTo.getId()), submitPayVo.getUid());
        if (!Objects.equals(res, 1L)) {
            //失败
            vo.setCode(1);
            return vo;
        } else {
            //成功
            OrderCreateTo orderCreateTo = orderCreate(submitPayVo);
            if (Math.abs(orderCreateTo.getOrderEntity().getPayAmount().subtract(submitPayVo.getTotalAmount()).doubleValue()) > 0.01) {
                //金额错误
                vo.setCode(2);
                return vo;
            } else {
                //验价成功
                //保存订单和订单项信息
                //保存订单
                saveOrderAndItems(orderCreateTo);

                //锁定库存 参数：锁的哪个skuId、锁几个、锁的订单号(后续根据订单号进行订单失败的可靠通知保证最终库存数量一致性)
                Map<Long, Integer> map = orderCreateTo.getOrderItemEntities().stream().collect(Collectors.toMap(OrderItemEntity::getSkuId, OrderItemEntity::getSkuQuantity));
                log.info("Seata全局事务id=================>{}", RootContext.getXID());
                R r = wareFeignService.lockInventory(map, orderCreateTo.getOrderEntity().getOrderSn());
                if (Objects.equals(r.getCode(), 0)) {
                    //成功
                    vo.setCode(0);
                    vo.setOrderEntity(orderCreateTo.getOrderEntity());
                    //订单创建成功、库存锁定成功，存入mq如果订单超时进行解锁库存取消订单
                    rabbitTemplate.convertAndSend(ORDER_EVENT_EXCHANGE, ORDER_CREATE_ORDER, orderCreateTo.getOrderEntity());
//                    int i = 10 / 0;
                    return vo;
                } else {
                    //失败
                    vo.setCode(3);
                    throw new RuntimeException(r.getCode() + ":" + r.get("msg"));
                }
            }
        }
    }

    //保存订单和订单项信息
    private void saveOrderAndItems(OrderCreateTo orderCreateTo) {
        OrderEntity orderEntity = orderCreateTo.getOrderEntity();
        List<OrderItemEntity> orderItemEntities = orderCreateTo.getOrderItemEntities();

        orderService.save(orderEntity);

        orderItemService.saveBatch(orderItemEntities);
    }

    //创建订单数据
    private OrderCreateTo orderCreate(SubmitPayVo submitPayVo) {
        OrderCreateTo createTo = new OrderCreateTo();
        //组装订单信息
        //远程获取用户地址信息
        MemberReceiveAddressVo addressVo = memberFeignService.getAddressFreight(submitPayVo.getAddrId());
        createTo.setFreight(addressVo.getFreight());

        OrderEntity orderEntity = new OrderEntity();
        String orderSn = IdUtil.nanoId();
        orderEntity.setOrderSn(orderSn);
        //设置收货人信息
        orderEntity.setCreateTime(new Date());
        orderEntity.setMemberId(addressVo.getMemberId());
        orderEntity.setMemberUsername(addressVo.getName());
        orderEntity.setReceiverCity(addressVo.getCity());
        orderEntity.setReceiverName(addressVo.getName());
        orderEntity.setFreightAmount(addressVo.getFreight());
        orderEntity.setReceiverDetailAddress(addressVo.getDetailAddress());
        orderEntity.setReceiverPhone(addressVo.getPhone());
        orderEntity.setReceiverPostCode(addressVo.getPostCode());
        orderEntity.setReceiverProvince(addressVo.getProvince());
        orderEntity.setReceiverRegion(addressVo.getRegion());

        //设置订单项
        List<MemberCartVo> memberCarts = cartFeignService.getMemberCarts();
        if (MyCollUtil.isNotEmpty(memberCarts)) {
            List<OrderItemEntity> orderItemEntityList = memberCarts.stream().map(po -> {
                OrderItemEntity orderItemEntity = orderItemCreate(po);
                orderItemEntity.setOrderSn(orderSn);
                return orderItemEntity;
            }).toList();

            //计算总订单金额信息
            orderRealAmount(orderEntity, orderItemEntityList);

            createTo.setOrderItemEntities(orderItemEntityList);
        }


        createTo.setOrderEntity(orderEntity);
        return createTo;

    }

    //计算总订单金额信息
    private void orderRealAmount(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntityList) {
        BigDecimal totalAmount = new BigDecimal("0.0");
        BigDecimal promotionAmount = new BigDecimal("0.0");
        BigDecimal integrationAmount = new BigDecimal("0.0");
        BigDecimal couponAmount = new BigDecimal("0.0");
        int integration = 0;
        int growth = 0;
        for (OrderItemEntity orderItemEntity : orderItemEntityList) {
            totalAmount = totalAmount.add(orderItemEntity.getRealAmount());
            promotionAmount = promotionAmount.add(orderItemEntity.getPromotionAmount());
            integrationAmount = integrationAmount.add(orderItemEntity.getIntegrationAmount());
            couponAmount = couponAmount.add(orderItemEntity.getCouponAmount());
            integration = integration + orderItemEntity.getGiftIntegration();
            growth = growth + orderItemEntity.getGiftGrowth();
        }
        //订单总额
        orderEntity.setTotalAmount(totalAmount);
        //应付总额
        orderEntity.setPayAmount(totalAmount.subtract(orderEntity.getFreightAmount()));
        //促销优化金额（促销价、满减、阶梯价）
        orderEntity.setPromotionAmount(promotionAmount);
        //积分抵扣金额
        orderEntity.setIntegrationAmount(integrationAmount);
        //优惠券抵扣金额
        orderEntity.setCouponAmount(couponAmount);
        orderEntity.setPayType(1);
        orderEntity.setSourceType(0);
        orderEntity.setStatus(0);
        orderEntity.setAutoConfirmDay(7);
        //可以获得的积分
        orderEntity.setIntegration(integration);
        //可以获得的成长值
        orderEntity.setGrowth(integration);
        orderEntity.setModifyTime(new Date());
        orderEntity.setDeleteStatus(0);
    }


    private OrderItemEntity orderItemCreate(MemberCartVo memberCartVo) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        SpuInfoTo spuInfoTo = productFeignService.listBySkuId(memberCartVo.getSkuId());
        if (!Objects.isNull(spuInfoTo)) {
            orderItemEntity.setSpuId(spuInfoTo.getId());
            orderItemEntity.setSpuBrand(spuInfoTo.getBrandName());
            orderItemEntity.setSpuName(spuInfoTo.getSpuName());
            orderItemEntity.setSpuPic(spuInfoTo.getPic());
            orderItemEntity.setCategoryId(spuInfoTo.getCatalogId());
        }
        orderItemEntity.setSkuId(memberCartVo.getSkuId());
        orderItemEntity.setSkuPrice(memberCartVo.getPrice());
        orderItemEntity.setSkuAttrsVals(StrUtil.join(";", memberCartVo.getSkuAttrs()));
        orderItemEntity.setSkuPic(memberCartVo.getImage());
        orderItemEntity.setSkuName(memberCartVo.getTitle());
        orderItemEntity.setSkuQuantity(memberCartVo.getCount());

        //积分成长值： 价格乘数量
        orderItemEntity.setGiftGrowth(memberCartVo.getPrice().multiply(new BigDecimal(memberCartVo.getCount())).intValue());
        orderItemEntity.setGiftIntegration(memberCartVo.getPrice().multiply(new BigDecimal(memberCartVo.getCount())).intValue());

        //商品促销分解金额
        orderItemEntity.setPromotionAmount(new BigDecimal("0.0"));
        //优惠券优惠分解金额
        orderItemEntity.setCouponAmount(new BigDecimal("0.0"));
        //积分优惠分解金额
        orderItemEntity.setIntegrationAmount(new BigDecimal("0.0"));
        //该商品经过优惠后的分解金额
        BigDecimal realAmount = memberCartVo.getTotalPrice()
                .subtract(orderItemEntity.getPromotionAmount())
                .subtract(orderItemEntity.getCouponAmount())
                .subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(realAmount);

        return orderItemEntity;
    }

}
